<?php

namespace App\Http\Services;

use App\Http\Model\FinanceUserWallet;
use App\Http\Model\Gift;
use App\Http\Model\Hint;
use App\Http\Model\Room;
use App\Http\Model\RoomUserProtect;
use App\Http\Model\User;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;

class RoomProtectServices extends CommonServices
{
    protected $roomUserProtectModel;
    protected $roomModel;
    protected $userModel;
    protected $financeWalteModle;
    protected $giftModel;

    protected $dayRoomProtectRedisKey = 'ROOM:USER:PROTECT:RANK:DAY:';//房间守护榜日榜
    protected $weekRoomProtectRedisKey = 'ROOM:USER:PROTECT:RANK:WEEK:';//房间守护周榜

    protected $error_log = 'error_roomProtect';

    public function __construct()
    {
        $this->roomUserProtectModel = new RoomUserProtect();
        $this->roomModel = new Room();
        $this->userModel = new User();
        $this->financeWalteModle = new FinanceUserWallet();
        $this->giftModel = new Gift();
    }

    //获取房间守护榜
    public function getRoomProtectRank($roomId, $userId, $type, $page, $limit){
        $code = Hint::SUCCESS;
        $data = [];
        $msg = 'ok';
        $page = $page+1;
        do{
            //查询房间模式是否是电台模式
            $roomInfo = $this->roomModel->get_room($roomId);
            if(empty($roomInfo) || $roomInfo['room_type']['id'] != 44){
                $code = Hint::ERR_NORMAL;
                $msg = '非电台房间无法查看!';
                break;
            }
            if($type == 1){
                $startTime = Carbon::now()->startOfDay()->toDateTimeString();
                $endTime = Carbon::now()->endOfDay()->toDateTimeString();
                $date = Carbon::now()->toDateString();
                $redisKey = $this->dayRoomProtectRedisKey.$date.':'.$roomId; // 日榜
            }else{
                $startTime = Carbon::now()->startOfWeek()->toDateTimeString();
                $endTime = Carbon::now()->endOfWeek()->toDateTimeString();
                $weekStart = Carbon::now()->startOfWeek()->toDateString();
                $weekEnd = Carbon::now()->endOfWeek()->toDateString();
                $redisKey = $this->weekRoomProtectRedisKey.$weekStart.'=>'.$weekEnd.':'.$roomId; //周榜
            }
            //查询排行榜
            $rankArr = $this->roomUserProtectModel->getRoomProtectRank($roomId, $type, $startTime, $endTime, $page, $limit);
            //查询用户信息
            $rankdata = [];
            if(!empty($rankArr)){
                foreach($rankArr as $k=>$val){
                    //查询对应守护等级
                    $userProtectInfo = $this->roomUserProtectModel->getUserProtectType($roomId, $k);
                    //若过期了则显示过期的信息
                    if(empty($userProtectInfo)){
                        $passedProtectInfo = $this->roomUserProtectModel->getUserPassedProtect($roomId, $k);
                    }
                   
                    $userInfo = $this->userModel->get_user($k);
                    //剩余时间秒数
                    $need = Carbon::parse($userProtectInfo['end_time']);
                    $diffTime = (new Carbon)->diffInSeconds($need,false);
                    if($diffTime < 0){
                        $diffTime = 0;
                    }
                    $rankdata[$k]['user_id'] = $userInfo['user_id'];
                    $rankdata[$k]['nickname'] = $userInfo['nickname'];
                    $rankdata[$k]['gender'] = $userInfo['gender'];
                    $rankdata[$k]['img'] = $userInfo['images'][0];
                    $rankdata[$k]['total'] = (int)$val;
                    $rankdata[$k]['protect_type'] = empty($userProtectInfo['protect_type']) ? $passedProtectInfo['protect_type'] : $userProtectInfo['protect_type'];
                    $rankdata[$k]['leave_time'] = $diffTime;
                }
            }
            $rankdata = array_values($rankdata);
            //重新排列
            foreach($rankdata as $k=>$v){
                $rankdata[$k]['rank'] = $page ? ($page * $limit - $limit + $k + 1) : $k;
            }
            //获取我的排行信息
            $myLevelScore = 0;
            $nowlevel = Redis::ZREVRANK($redisKey,$userId);
            //我目前值
            $myLevelScore = Redis::ZSCORE($redisKey,$userId);

            $sortLevel = Redis::zrevrange($redisKey,0,-1);

            if(isset($sortLevel[$nowlevel-1])){
                $upLevel = $sortLevel[$nowlevel-1];
                //查询对应socre值
                $upLevelScore = Redis::ZSCORE($redisKey,$upLevel);
                //我目前值
                $myLevelScore = Redis::ZSCORE($redisKey,$userId);
            }else{
                $diffLevel = 0; //相差礼物数
            }
            if(is_null($nowlevel)){
                $level = 0; //目前排名
            }elseif($nowlevel == 0){
                $level = 1; //目前排名
            }elseif($nowlevel > 99){
                $level = $nowlevel; //目前排名
            }else{
                $level = $nowlevel+1;//默认第一名从0开始要加1后面的
            }
            //获取用户个人信息
            $loginUserInfo = $this->userModel->get_user($userId);
            //获取守护信息
            $getLoginPortectInfo = $this->roomUserProtectModel->getUserProtectType($roomId, $userId);
            //若过期了则显示过期的信息
            if(empty($getLoginPortectInfo)){
                $passedProtectInfo = $this->roomUserProtectModel->getUserPassedProtect($roomId, $userId);
            }
            //剩余时间秒数
            $need = Carbon::parse($getLoginPortectInfo['end_time']);
            $diffTime = (new Carbon)->diffInSeconds($need,false);
            if($diffTime < 0){
                $diffTime = 0;
            }
            $myLevel = [
                'rank' => $level,
                'nickname' => $loginUserInfo['nickname'],
                'img' => $loginUserInfo['images'][0],
                'gender' => $loginUserInfo['gender'],
                'total' => empty($myLevelScore) ? 0 : $myLevelScore,
                'protectInfo' => empty($getLoginPortectInfo) ? $passedProtectInfo : $getLoginPortectInfo,
                'leave_time' =>  $diffTime,
            ];
            $data['rankList'] = $rankdata;
            $data['myLevelInfo'] = $myLevel;
        }while(false);
        return compact('code','data','msg');
    }

    //获取房间守护商品
    public function getRoomProtectList($roomId, $userId){
        $code = Hint::SUCCESS;
        $data = [];
        $msg = 'ok';
        do{
            //查询房间模式是否是电台模式
            $roomInfo = $this->roomModel->get_room($roomId);
            if(empty($roomInfo) || $roomInfo['room_type']['id'] != 44){
                $code = Hint::ERR_NORMAL;
                $msg = '非电台房间无法查看!';
                break;
            }
            $data = $this->roomUserProtectModel->getUserProtectList($roomId, $userId);
        }while(false);
        return compact('code','data','msg');
    }

    //购买服务弹窗
    public function payServiceNotice($userId,$service_id,$roomId){
        $code = Hint::SUCCESS;
        $data = [];
        $msg = 'ok';
        do{
            if(empty($userId)){
                $code = Hint::PARAM_ERROR;
                $msg = '登录失效';
                break;
            }
            if(empty($roomId)){
                $code = Hint::PARAM_ERROR;
                $msg = '缺少参数';
                break;
            }
            //查看用户现有等级
            $nowProtectInfo = $this->roomUserProtectModel->getUserProtectType($roomId, $userId);
            //开通服务详情
            $openServiceInfo = $this->roomUserProtectModel->getProtectInfo($service_id);
            if(empty($openServiceInfo['gift_id'])){
                $code = Hint::PARAM_ERROR;
                $msg = '缺少参数';
                break;
            }
            //获取礼物价格
            $giftInfo = $this->giftModel->get_gift($openServiceInfo['gift_id']);
            if(empty($nowProtectInfo)){//开通
                $endTime = Carbon::now()->addDays($openServiceInfo['day'])->toDateTimeString();
                $code = Hint::SUCCESS;
                $data = [
                    'diamond' => $giftInfo['price'],
                    'protect_name' => $openServiceInfo['name'],
                    'protect_type' => $openServiceInfo['id'],
                    'endTime' =>  $endTime,
                    'pay_type' => 1,//开通
                    'oldInfo' => new \stdClass,
                ];
                break;
            }elseif(!empty($nowProtectInfo)){
                //续费
                if($nowProtectInfo['protect_type'] < $openServiceInfo['id']){
                    //降级续费
                    $endTime = Carbon::parse($nowProtectInfo['end_time'])->addDays($openServiceInfo['day'])->toDateTimeString();
                    $code = Hint::SUCCESS;
                    $oldServiceInfo =  $this->roomUserProtectModel->getProtectInfo($nowProtectInfo['protect_type']);
                    $nowProtectInfo['protect_name'] = $oldServiceInfo['name'];
                    $data = [
                        'diamond' => $giftInfo['price'],
                        'protect_name' => $openServiceInfo['name'],
                        'protect_type' => $openServiceInfo['id'],
                        'endTime' =>  $endTime,
                        'pay_type' => 4,//降级续费
                        'oldInfo' => $nowProtectInfo,
                    ];
                    break;
                }elseif($nowProtectInfo['protect_type'] == $openServiceInfo['id']){
                    //正常续费
                    $endTime = Carbon::parse($nowProtectInfo['end_time'])->addDays($openServiceInfo['day'])->toDateTimeString();
                    $code = Hint::SUCCESS;
                    $data = [
                        'diamond' => $giftInfo['price'],
                        'protect_name' => $openServiceInfo['name'],
                        'protect_type' => $openServiceInfo['id'],
                        'endTime' =>  $endTime,
                        'oldInfo' => new \stdClass,
                        'pay_type' => 2,//正常续费
                    ];
                    break;
                }elseif($nowProtectInfo['protect_type'] > $openServiceInfo['id']){
                    //升级
                    $oldEndTime = $nowProtectInfo['end_time'];
                    $endTime = Carbon::parse($nowProtectInfo['end_time']);
                    $leaveTime = (new Carbon)->diffInMinutes($endTime,true);
                    //扣除钻石 = 剩余时长(分钟数)*目标等级每分钟钻石数-剩余时长分钟数*当前等级每分钟钻石数
                    $oldServiceInfo =  $this->roomUserProtectModel->getProtectInfo($nowProtectInfo['protect_type']);
                    $costDiamond = ($leaveTime*$openServiceInfo['hour_diamond']) - ($leaveTime*$oldServiceInfo['hour_diamond']);
                    $code = Hint::SUCCESS;
                    $data = [
                        'diamond' => ceil($costDiamond),
                        'protect_name' => $openServiceInfo['name'],
                        'protect_type' => $openServiceInfo['id'],
                        'endTime' =>  $oldEndTime,
                        'oldInfo' => new \stdClass,
                        'pay_type' => 3,//升级
                    ];
                    break;
                }
            }
        }while(false);
        return compact('code','data','msg');
    }

    //购买服务处理
    public function payService($userId, $pay_type, $service_id, $to_user_id, $roomId){
        $code = Hint::SUCCESS;
        $data = [];
        $msg = 'ok';
        do{
            if(empty($userId)){
                $code = Hint::PARAM_ERROR;
                $msg = '登录失效';
                break;
            }
            if(empty($pay_type)){
                $code = Hint::PARAM_ERROR;
                $msg = '缺少参数';
                break;
            }
            if(empty($service_id)){
                $code = Hint::PARAM_ERROR;
                $msg = '请选择购买的服务';
                break;
            }
            if(empty($to_user_id)){
                $code = Hint::PARAM_ERROR;
                $msg = '主播不在房间，请稍后开通';
                break;
            }
            if(empty($roomId)){
                $code = Hint::PARAM_ERROR;
                $msg = '不在房间内';
                break;
            }
            //检查登录用户钻石数是否够
            $userWalte = $this->financeWalteModle->get_wallet($userId);
            //获取服务原始金额
            $serviceInfo = $this->roomUserProtectModel->getProtectInfo($service_id);
            //获取礼物价格
            $giftInfo = $this->giftModel->get_gift($serviceInfo['gift_id']);
            //计算消耗钻石数
            $payInfo['costDiamond'] = 0;
            if($pay_type == 1){ //开通支付信息
                $payInfo = [
                    'costDiamond' => $giftInfo['price'],
                    'serivceId' => $serviceInfo['id'],
                    'day' => $serviceInfo['day'],
                    'type' => $pay_type,
                    'gift_id' => $serviceInfo['gift_id'],
                ];
            }elseif($pay_type == 2){//续费支付信息
                $payInfo = [
                    'costDiamond' => $giftInfo['price'],
                    'serivceId' => $serviceInfo['id'],
                    'day' => $serviceInfo['day'],
                    'type' => $pay_type,
                    'gift_id' => $serviceInfo['gift_id'],
                ];
            }elseif($pay_type == 3){//升级支付信息
                //获取用户目前守护信息
                $nowProtectInfo = $this->roomUserProtectModel->getUserProtectType($roomId, $userId);
                if(empty($nowProtectInfo)){
                    $code = Hint::ERR_NORMAL;
                    $msg = '服务已过期';
                    break;
                }
                //老服务信息
                $oldServiceInfo = $this->roomUserProtectModel->getProtectInfo($nowProtectInfo['protect_type']);
                //剩余时长
                $endTime = Carbon::parse($nowProtectInfo['end_time']);
                $leaveTime = (new Carbon)->diffInMinutes($endTime,true);
                //扣除钻石 = 剩余时长(分钟数)*目标等级每分钟钻石数-剩余时长分钟数*当前等级每分钟钻石数
                $costDiamond = ($leaveTime*$serviceInfo['hour_diamond']) - ($leaveTime*$oldServiceInfo['hour_diamond']);
                $payInfo = [
                    'costDiamond' => ceil($costDiamond),
                    'serivceId' => $serviceInfo['id'],
                    'day' => $serviceInfo['day'],
                    'type' => $pay_type,
                    'gift_id' => $serviceInfo['gift_id'],
                ];
            }elseif($pay_type == 4){
                $payInfo = [
                    'costDiamond' => $giftInfo['price'],
                    'serivceId' => $serviceInfo['id'],
                    'day' => $serviceInfo['day'],
                    'type' => $pay_type,
                    'gift_id' => $serviceInfo['gift_id'],
                ];
            }
            if($payInfo['costDiamond'] > $userWalte['diamond_balance']){
                $code = Hint::DIAMOND_NOT_ENOUGH;
                $msg = '钻石不足支付';
                break;
            }
            //调用购买服务
            $giftService = new SendGiftServices();
            $giftService = $giftService->sendGiftByDiamond($userId,[$to_user_id],$payInfo['gift_id'],1,$roomId,0,$payInfo);
            if($giftService['code'] != Hint::SUCCESS){
                $code = $giftService['code'];
                $msg = $giftService['message'];
                break;
            }
        }while(false);
        return compact('code','msg','data');
    }

    //开通续费升级处理
    public function doPayHandel($giftId, $fromUserId, $toUserId, $roomId, $extData){
        //获取对应服务下的信息
        $serviceInfo = $this->roomUserProtectModel->getProtectInfo($extData['serivceId']);
        try{
            DB::beginTransaction();
            //分情况处理
            if($extData['type'] == 1){//开通服务
                //入库
                $startTime = Carbon::now()->toDateTimeString();
                $endTime = Carbon::parse($startTime)->addDays($serviceInfo['day'])->toDateTimeString();
                $data = [
                    'user_id' => $fromUserId,
                    'protect_type' => $serviceInfo['id'],
                    'start_time' => $startTime,
                    'end_time' => $endTime,
                    'room_id' => $roomId,
                    'created_at' => Carbon::now()->toDateTimeString(),
                ];
                $streamData = [
                    'user_id' => $fromUserId,
                    'room_id' => $roomId,
                    'protect_type' => $serviceInfo['id'],
                    'diamond' => $extData['costDiamond'],
                    'to_user_id' => $toUserId,
                    'gift_id' => $giftId,
                    'created_at' => Carbon::now(),
                    'type' => $extData['type'],
                ];
                $this->roomUserProtectModel->insertUserProtect($data);
                $this->roomUserProtectModel->insertProtectStream($streamData);
                //缓存更新
                $this->upDateRankRedis($roomId, $extData['costDiamond'], $fromUserId);
            }elseif($extData['type'] == 2){//续费服务
                //查询用户原来的等级
                $oldServiceInfo = $this->roomUserProtectModel->getUserProtectType($roomId, $fromUserId);
                $startTime = $oldServiceInfo['end_time'];
                $endTime = Carbon::parse($startTime)->addDays($serviceInfo['day'])->toDateTimeString();
                $data = [
                    'user_id' => $fromUserId,
                    'protect_type' => $serviceInfo['id'],
                    'end_time' => $endTime,
                    'room_id' => $roomId,
                    'updated_at' => Carbon::now()->toDateTimeString(),
                ];
                $streamData = [
                    'user_id' => $fromUserId,
                    'room_id' => $roomId,
                    'protect_type' => $serviceInfo['id'],
                    'diamond' => $extData['costDiamond'],
                    'to_user_id' => $toUserId,
                    'gift_id' => $giftId,
                    'created_at' => Carbon::now()->toDateTimeString(),
                    'type' => $extData['type'],
                ];
                $this->roomUserProtectModel->updateUserProtect($data, $oldServiceInfo['id'], $roomId);
                $this->roomUserProtectModel->insertProtectStream($streamData);
                //缓存更新
                $this->upDateRankRedis($roomId, $extData['costDiamond'], $fromUserId);
            }elseif($extData['type'] == 3){//升级服务
                //查询用户原来的等级
                $oldServiceInfo = $this->roomUserProtectModel->getUserProtectType($roomId, $fromUserId);

                $data = [
                    'user_id' => $fromUserId,
                    'protect_type' => $serviceInfo['id'],
                    'updated_at' => Carbon::now()->toDateTimeString(),
                ];
                $streamData = [
                    'user_id' => $fromUserId,
                    'room_id' => $roomId,
                    'protect_type' => $serviceInfo['id'],
                    'diamond' => $extData['costDiamond'],
                    'to_user_id' => $toUserId,
                    'gift_id' => $giftId,
                    'created_at' => Carbon::now()->toDateTimeString(),
                    'type' => $extData['type'],
                ];
                $this->roomUserProtectModel->updateUserProtect($data, $oldServiceInfo['id'], $roomId);
                $this->roomUserProtectModel->insertProtectStream($streamData);
                //缓存更新
                $this->upDateRankRedis($roomId, $extData['costDiamond'], $fromUserId);
            }elseif($extData['type'] == 4){//降级续费
                //查询用户原来的等级
                $oldServiceInfo = $this->roomUserProtectModel->getUserProtectType($roomId, $fromUserId);
                $startTime = $oldServiceInfo['end_time'];
                $endTime = Carbon::parse($startTime)->addDays($serviceInfo['day'])->toDateTimeString();
                $data = [
                    'user_id' => $fromUserId,
                    'protect_type' => $serviceInfo['id'],
                    'start_time' => $startTime,
                    'end_time' => $endTime,
                    'room_id' => $roomId,
                    'created_at' => Carbon::now()->toDateTimeString(),
                ];
                $streamData = [
                    'user_id' => $fromUserId,
                    'room_id' => $roomId,
                    'protect_type' => $serviceInfo['id'],
                    'diamond' => $extData['costDiamond'],
                    'to_user_id' => $toUserId,
                    'gift_id' => $giftId,
                    'created_at' => Carbon::now()->toDateTimeString(),
                    'type' => $extData['type'],
                ];
                $this->roomUserProtectModel->insertUserProtect($data);
                $this->roomUserProtectModel->insertProtectStream($streamData);
                //缓存更新
                $this->upDateRankRedis($roomId, $extData['costDiamond'], $fromUserId);
            }
            DB::commit();
        }catch(\Exception $e){
            DB::rollBack();
            write_log($this->error_log,'ERROR 购买服务失败',['msg'=>$e->getMessage(),'param'=>$extData,'user_id'=>$fromUserId]);
        }
        
    }

    //用户送礼增加排行榜值
    public function incProtectRank($user_id, $total, $roomId){
        //查询送礼用户在房间下是否是守护用户
        $protectInfo = $this->roomUserProtectModel->getUserProtectType($roomId, $user_id);
        $roomInfo = $this->roomModel->get_room($roomId);
        if(!empty($protectInfo) && $roomInfo['room_type']['id'] == 44){
            $this->upDateRankRedis($roomId, $total, $user_id);
        }
    }

    //更新榜单缓存
    public function upDateRankRedis($roomId, $total, $user_id){
        //日榜
        $date = Carbon::now()->toDateString();
        $dayRedisKey = $this->dayRoomProtectRedisKey.$date.':'.$roomId; // 日榜
        $dayExperTime = 86400;
        //周榜
        $weekStart = Carbon::now()->startOfWeek()->toDateString();
        $weekEnd = Carbon::now()->endOfWeek()->toDateString();
        $weekRedisKey = $this->weekRoomProtectRedisKey.$weekStart.'=>'.$weekEnd.':'.$roomId; //周榜
        $weekExperTime = 7*86400;
        
        //新增或者更新排行榜数据
        Redis::ZINCRBY($dayRedisKey,$total,$user_id);
        if(!Redis::EXISTS($dayRedisKey)){
            Redis::EXPIRE($dayRedisKey,$dayExperTime);//一天
        }
        //新增或者更新排行榜数据
        Redis::ZINCRBY($weekRedisKey,$total,$user_id);
        if(!Redis::EXISTS($weekRedisKey)){
            Redis::EXPIRE($weekRedisKey,$weekExperTime);//一周
        }
    }
}